import { Billing } from "@opencode-ai/console-core/billing.js" import { createAsync, query, useParams } from "@solidjs/router" import { createMemo, For, Show, createEffect, createSignal } from "solid-js" import { formatDateUTC, formatDateForTable } from "../common" import { withActor } from "~/context/auth.withActor" import { IconChevronLeft, IconChevronRight, IconBreakdown } from "~/component/icon" import styles from "./usage-section.module.css" import { createStore } from "solid-js/store" const PAGE_SIZE = 50 async function getUsageInfo(workspaceID: string, page: number) { "use server" return withActor(async () => { return await Billing.usages(page, PAGE_SIZE) }, workspaceID) } const queryUsageInfo = query(getUsageInfo, "usage.list") export function UsageSection() { const params = useParams() const usage = createAsync(() => queryUsageInfo(params.id!, 0)) const [store, setStore] = createStore({ page: 0, usage: [] as Awaited> }) const [openBreakdownId, setOpenBreakdownId] = createSignal(null) createEffect(() => { setStore({ usage: usage() }) }, [usage]) createEffect(() => { if (!openBreakdownId()) return const handleClickOutside = (e: MouseEvent) => { const target = e.target as HTMLElement if (!target.closest('[data-slot="tokens-with-breakdown"]')) { setOpenBreakdownId(null) } } document.addEventListener("click", handleClickOutside) return () => document.removeEventListener("click", handleClickOutside) }) const hasResults = createMemo(() => store.usage && store.usage.length > 0) const canGoPrev = createMemo(() => store.page > 0) const canGoNext = createMemo(() => store.usage && store.usage.length === PAGE_SIZE) const calculateTotalInputTokens = (u: Awaited>[0]) => { return u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWrite5mTokens ?? 0) + (u.cacheWrite1hTokens ?? 0) } const calculateTotalOutputTokens = (u: Awaited>[0]) => { return u.outputTokens + (u.reasoningTokens ?? 0) } const goPrev = async () => { const usage = await getUsageInfo(params.id!, store.page - 1) setStore({ page: store.page - 1, usage, }) } const goNext = async () => { const usage = await getUsageInfo(params.id!, store.page + 1) setStore({ page: store.page + 1, usage, }) } return (

Usage History

Recent API usage and costs.

Make your first API call to get started.

} > {(usage, index) => { const date = createMemo(() => new Date(usage.timeCreated)) const totalInputTokens = createMemo(() => calculateTotalInputTokens(usage)) const totalOutputTokens = createMemo(() => calculateTotalOutputTokens(usage)) const inputBreakdownId = `input-breakdown-${index()}` const outputBreakdownId = `output-breakdown-${index()}` const isInputOpen = createMemo(() => openBreakdownId() === inputBreakdownId) const isOutputOpen = createMemo(() => openBreakdownId() === outputBreakdownId) const isClaude = usage.model.toLowerCase().includes("claude") return ( ) }}
Date Model Input Output Cost
{formatDateForTable(date())} {usage.model}
e.stopPropagation()}> setOpenBreakdownId(null)}>{totalInputTokens()}
e.stopPropagation()}>
Input {usage.inputTokens}
Cache Read {usage.cacheReadTokens ?? 0}
Cache Write {usage.cacheWrite5mTokens ?? 0}
e.stopPropagation()}> setOpenBreakdownId(null)}>{totalOutputTokens()}
e.stopPropagation()}>
Output {usage.outputTokens}
Reasoning {usage.reasoningTokens ?? 0}
${((usage.cost ?? 0) / 100000000).toFixed(4)}
) }